# Horloge vectorielle locale
# 	contient trois champs:
#		salonId : identifiant du contact
#		noeudId : identifiant du noeud distant
#		numAction : numero de derniere action connue du contact
#
# Les deux premiers champs peuvent etre assimile a une clef binaire donnant
# comme seule information le numero d'action
#
# +-----------------------+
# |           |           +    +-------------+
# |  salonId  |  noeudId -+--> |  numAction  |
# |           |           +    +-------------+
# +-----------------------+
# |           |           +    +-------------+
# |  salonId  |  noeudId -+--> |  numAction  |
# |           |           +    +-------------+
# +-----------------------+
# | ....                  |
#
global var_vecteurHorloge
set var_horlogeCourant { }

################################################################################
#
# Retourne le numero d'action d'un noeud donnee dans une horloge passee en
# parametre
#
# => param_noeudId : identifiant du noeud distant
# => param_horloge : horloge distante dans laquelle on recherche le numero
#                    d'action
# <= numero de derniere action connue trouve dans l'horloge distante
#
################################################################################
proc proc_getNumActionNoeud { param_noeudId param_horloge } {
	# Formatte l'horloge sous forme de tableau
	array set var_horlogeMessageCourant [proc_strToArrayHorloge $param_horloge]
	
	return $var_horlogeMessageCourant($param_noeudId,numAction)
}


################################################################################
#
# Teste si les donnees ont deja ete recues
# 	compare le numero d'action (1) correspondant a l'initiateur du message avec
#		le dernier numero d'action (2) de ce noeud connu en local
#		si (1) <= (2),les donnees sont redondantes
#
# => param_salonId : numero du salon au sein duquel le message a ete envoye
# => param_initId : indentifiant du noeud emetteur du message
# => param_horloge : horloge distante
#
################################################################################
proc proc_dejaMessage { param_salonId param_initId param_horloge } {
	global var_vecteurHorloge
	
	# On ne lit pas nos propre message
	if { $param_initId == [proc_getMonId] } {
		return 1
	}
	
	# Formatte l'horloge distante du message
	array set var_horlogeMessageCourant [proc_strToArrayHorloge $param_horloge]
	
	# Teste si on connait l'initiateur
	if { [info exists var_vecteurHorloge($param_salonId,$param_initId) ] == 1 } {
		# Compare les numero d'actions de l'horloge du message et locale
		if { $var_vecteurHorloge($param_salonId,$param_initId,numAction) >= $var_horlogeMessageCourant($param_initId,numAction) } {
			# Le numero d'action local est superieur ou egal a celui du message,
			# 	donnees redondantes
			return 1
		} else {
			# Le numero d'action local est inferieur,on prend les donnees
			return 0
		}
	} else {
		# On connait pas l'initiateur,on n'a pas les donnees
		return 0
	}
}

################################################################################
#
# Procedure permettant d'ajouter ou de mettre a jour un noeud dans l'horloge
#
# => param_salonId : identifiant du salon auquel participe le noeud distant
# => param_noeudId : identifiant du noeud distant
# => param_numAction : numero d'action correspondant au message relatif a l'horloge du noeud distant
#
# <= 0 si le noeud a ete mis a jour, 1 si le noeud a ete
################################################################################
proc proc_majNoeudHorloge { param_salonId param_noeudId param_numAction } {
	global var_vecteurHorloge
	
	# Si on est l'initiateur du message, on ne met pas a jour l'horloge locale
	if { $param_noeudId == [ proc_getMonId ] } {
		return 0
	}

	# Si on connait l'initiateur du message
	if { [info exists var_vecteurHorloge($param_salonId,$param_noeudId)] } {
		# Met a jour l'horloge avec le numero max d'action
		if { $param_numAction > $var_vecteurHorloge($param_salonId,$param_noeudId,numAction) } {
			set var_vecteurHorloge($param_salonId,$param_noeudId,numAction) $param_numAction
			set var_vecteurHorloge($param_salonId,$param_noeudId,validite) 0
			
		}
		# Indique une mise a jour
		return 0
	} else {
		# Declare le nouveau contact
		set var_vecteurHorloge($param_salonId,$param_noeudId) $param_noeudId
		set var_vecteurHorloge($param_salonId,$param_noeudId,numAction) $param_numAction
		set var_vecteurHorloge($param_salonId,$param_noeudId,validite) 0
		# Indique la declaration d'un nouveau contact
		return 1
	}
}

################################################################################
# Declaration d'un nouveau salon a ajouter dans l'horloge
################################################################################
proc proc_addSalonHorloge { param_salonId } {
	global var_vecteurHorloge
	set var_vecteurHorloge($param_salonId) 0
}

################################################################################
# Suppression d'un salon dans l'horloge
################################################################################
proc proc_supSalonHorloge { param_salonId } {
	global var_vecteurHorloge
	unset var_vecteurHorloge($param_salonId)
}

################################################################################
# Declaration d'une nouvelle action locale qui influe sur l'etat des contacts
################################################################################
proc proc_addAction { param_salonId } {
	global var_vecteurHorloge
	set var_vecteurHorloge($param_salonId) [expr $var_vecteurHorloge($param_salonId)  + 1]
}

################################################################################
# Decoupe une horloge en chaine de caracteres en tableau
#
# => id1,numAction1,dateValidite1,flag1;id2,numAction2,dateValidite2,flag2;...
#
#    les flags sont des informations supplementaires permettant de synchroniser
#		 les messages
# 
# <= +-----+
#    |     |    +------------+---------------+-------+
#    | id1 +--> | numAction1 | dateValidite1 | flag1 |
#    |     |    +------------+---------------+-------+
#    +-----+
#    |     |    +------------+---------------+-------+
#    | id2 +--> | numAction2 | dateValidite2 | flag2 |
#    |     |    +------------+---------------+-------+
#    +-----+
################################################################################
proc proc_strToArrayHorloge { param_horloge } {

	# Decoupe les triplets id,numAction,dateValidite
	set var_listeParamHorloge [split $param_horloge ";"]
	
	# Pour chque triplet
	foreach var_listeNoeud $var_listeParamHorloge  {
		# Recupere chaque champs
		set var_HorlogeNoeud [split $var_listeNoeud ","]
		set var_idNodeDist [lindex $var_HorlogeNoeud 0]
		set var_numActionDist [lindex $var_HorlogeNoeud 1]
		
		# Insere un contact dans l'horloge
		set var_horlogeMessageCourant($var_idNodeDist) $var_idNodeDist
		set var_horlogeMessageCourant($var_idNodeDist,numAction) $var_numActionDist
		#set var_horlogeMessageCourant($var_idNodeDist,flags) [lindex $var_HorlogeNoeud 2]
		
	}
	
	return [array get var_horlogeMessageCourant]
}

################################################################################
# Retourne l'horloge locale sous forme de chaine de caracteres avec anticipation
#		de reception des voisins
#
# => +-----+
#    |     |    +------------+---------------+
#    | id1 +--> | numAction1 | dateValidite1 |
#    |     |    +------------+---------------+
#    +-----+
#    |     |    +------------+---------------+
#    | id2 +--> | numAction2 | dateValidite2 |
#    |     |    +------------+---------------+
#    +-----+
#
# <= id1,numAction1,dateValidite1,flag1;id2,numAction2,dateValidite2,flag2;...
# 
################################################################################
proc proc_getHorloge { param_salonId } {
	global var_vecteurHorloge
	
	# Insere nos propres informations
	set var_horloge "[proc_getMonId],$var_vecteurHorloge($param_salonId)"
	
	# Ajoute chaque contact connu
	foreach var_idNoeud [array names var_vecteurHorloge -regexp "\^$param_salonId,\[\^,\]*\$"]  {
		if { $var_horloge != "" } {
			set var_horloge "$var_horloge;"
		}
		
		set var_horloge "$var_horloge$var_vecteurHorloge($var_idNoeud),$var_vecteurHorloge($param_salonId,$var_vecteurHorloge($var_idNoeud),numAction)"
	}

	return $var_horloge
}

################################################################################
# Retourne une horloge flaguee sous forme de tableau en chaine de caracteres
#
# => +-----+
#    |     |    +------------+---------------+-------+
#    | id1 +--> | numAction1 | dateValidite1 | flag1 |
#    |     |    +------------+---------------+-------+
#    +-----+
#    |     |    +------------+---------------+-------+
#    | id2 +--> | numAction2 | dateValidite2 | flag2 |
#    |     |    +------------+---------------+-------+
#    +-----+
#
# <= id1,numAction1,dateValidite1,flag1;id2,numAction2,dateValidite2,flag2;...
#
################################################################################
proc proc_formatHorloge { param_vecteurHorloge } {
	set var_horloge ""
	array set var_vecteurHorloge $param_vecteurHorloge
	
	foreach var_idNoeud [array names var_vecteurHorloge -regexp {^[^,]*$}]  {
		if { $var_horloge != "" } {
			set var_horloge "$var_horloge;"
		}
		set var_horloge "$var_horloge$var_idNoeud,$var_vecteurHorloge($var_idNoeud,numAction)"
		#,$var_vecteurHorloge($var_idNoeud,flags)"
	}

	return $var_horloge
}



################################################################################
# Retourne une horloge flaguee sous forme de tableau en chaine de caracteres
#
# => +-----+
#    |     |    +------------+---------------+-------+
#    | id1 +--> | numAction1 | dateValidite1 | flag1 |
#    |     |    +------------+---------------+-------+
#    +-----+
#    |     |    +------------+---------------+-------+
#    | id2 +--> | numAction2 | dateValidite2 | flag2 |
#    |     |    +------------+---------------+-------+
#    +-----+
#
# <= id1,numAction1,dateValidite1,flag1;id2,numAction2,dateValidite2,flag2;...
#
################################################################################
proc proc_traiterHorlogeMessage { param_salonId param1_horlogeMessageCourant} {
	set param_horlogeMessageCourant [proc_strToArrayHorloge $param1_horlogeMessageCourant]
	
	# tableau contenant l'horloge vectorielle locale
	global var_vecteurHorloge
	
	# tableau contenant l'horloge vectorielle du message recu
	array set var_horlogeMessageCourant $param_horlogeMessageCourant
	
	# le message va t'il etre retransmis
	set var_forward 0
	
	# liste des contacts connus dans le message
	set var_listeNoeudARedistribuer {}
	
	# traite les id de l'horloge vectorielle recue
	foreach var_idNoeud [array names var_horlogeMessageCourant -regexp {^[^,]*$}]  {
	
		# si l'id ne correspond pas a notre propre id
		if { $var_idNoeud != [proc_getMonId] } {
			# enregistre l'id s'il n'est pas connu en local
			proc_majNoeudHorloge $param_salonId $var_idNoeud $var_horlogeMessageCourant($var_idNoeud,numAction)
		}
	}
}



